package com.tomato.commons.email;

import com.tomato.commons.errors.CommonErrorType;
import com.tomato.commons.exception.ApplicationException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.mail.Authenticator;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeUtility;
import java.util.Date;
import java.util.Properties;

import static java.text.MessageFormat.format;

public class EmailBuilder {

    private static final Logger log = LoggerFactory.getLogger(EmailBuilder.class);

    private final EmailUtils emailUtils = new EmailUtils();


    /**
     * 设置邮箱类型
     *
     * @param type 邮箱类型 尽支持 icmp pop3 stmp 三种
     * @param host 邮箱服务器地址 支持 ip和域名 如 smtp.qq.com
     * @param port 邮箱服务器端口 如 465
     *             * @param sender 发件人邮箱 例如 123456@qq.com
     * @return passsword 发件人密码 例如 xx，如果是qq邮箱则是授权吗
     */
    public EmailBuilder config(EmailType type, String host, Integer port, String sender, String password) {
        Properties emailServerInfo = new Properties();
        emailUtils.setEmailServerInfo(emailServerInfo);
        emailUtils.setType(type);
        emailUtils.setSender(sender);
        emailUtils.setPassword(password);

        String proto = type.getProto();

        String hostKey = format("mail.{0}.host", proto);
        String protoKey = format("mail.{0}.protocol", proto);
        String portKey = format("mail.{0}.port", proto);
        String authKey = format("mail.{0}.auth", proto);
        String connectKey = format("mail.{0}.connectiontimeout", proto);
        String writeKey = format("mail.{0}.writetimeout", proto);
        String readKey = format("mail.{0}.timeout", proto);

        // 设置host
        emailServerInfo.setProperty(hostKey, host);
        // 设置协议
        emailServerInfo.setProperty(protoKey, proto);
        // 设置 端口
        emailServerInfo.setProperty(portKey, port.toString());
        // 设置是否需要请求认证
        emailServerInfo.setProperty(authKey, "true");

        // 设置超时时长 默认60s
        emailServerInfo.setProperty(connectKey, "60000");
        emailServerInfo.setProperty(writeKey, "60000");
        emailServerInfo.setProperty(readKey, "60000");
        return this;
    }

    public EmailBuilder security(Boolean security) {
        isSettingServerInfo();
        Properties serverInfo = emailUtils.getEmailServerInfo();
        EmailType type = emailUtils.getType();

        if (security) {
            String protoName = type.getProto();
            serverInfo.setProperty(format("mail.{0}.socketFactory.class", protoName), "javax.net.ssl.SSLSocketFactory");
            serverInfo.setProperty(format("mail.{0}.socketFactory.fallback", protoName), "false");
            serverInfo.setProperty(format("mail.{0}.socketFactory.port", protoName), format("mail.{0}.port", protoName));
        }
        return this;
    }


    /**
     * 连接服务器超时时长
     *
     * @param timeout 单位 毫秒
     * @return
     */
    public EmailBuilder connectionTimeout(long timeout) {
        isSettingServerInfo();
        Properties serverInfo = emailUtils.getEmailServerInfo();
        EmailType type = emailUtils.getType();

        String connectKey = format("mail.{0}.connectiontimeout", type.getProto());

        serverInfo.setProperty(connectKey, String.valueOf(timeout));
        return this;
    }


    /**
     * 读取邮件时长
     *
     * @param timeout 单位 毫秒
     * @return
     */
    public EmailBuilder readTimeout(long timeout) {
        isSettingServerInfo();
        Properties serverInfo = emailUtils.getEmailServerInfo();
        EmailType type = emailUtils.getType();
        String readKey = format("mail.{0}.timeout", type.getProto());
        // 设置超时时长 默认60s
        serverInfo.setProperty(readKey, "60000");
        return this;
    }

    /**
     * 读取邮件时长
     *
     * @param timeout 单位 毫秒
     * @return
     */
    public EmailBuilder sendTimeout(long timeout) {
        isSettingServerInfo();
        Properties serverInfo = emailUtils.getEmailServerInfo();
        EmailType type = emailUtils.getType();
        String writeKey = format("mail.{0}.writetimeout", type.getProto());
        // 设置超时时长 默认60s
        serverInfo.setProperty(writeKey, String.valueOf(timeout));
        return this;
    }


    /**
     * 判断是否配置了邮箱服务器信息
     */
    private void isSettingServerInfo() {
        Properties serverInfo = emailUtils.getEmailServerInfo();
        EmailType type = emailUtils.getType();

        if (serverInfo == null || type == null) {
            log.error(">>>>操作请配置邮箱信息信息<<<<");
            throw new ApplicationException(CommonErrorType.EMAIL_ERROR);
        }
    }


    /**
     * 邮件发送
     *
     * @param message 邮件信息
     */
    public void send(EmailMessage message) {
        try {
            Session session = createSession();
            MimeMessage msg = new MimeMessage(session);
            // 设置发件人
            msg.setFrom(InternetAddress.parse(MimeUtility.decodeText(emailUtils.getSender()))[0]);


            // 设置收件人 to类型代表收件人 cc类型代表邮件抄送，bcc为秘密抄送
            msg.setRecipients(MimeMessage.RecipientType.TO, trans(message.getRecipient()));

            // 如果抄送的人不为空设置为抄送人
            if (StringUtils.isNotBlank(message.getMakeACopyFor())) {
                msg.setRecipients(MimeMessage.RecipientType.CC, trans(message.getMakeACopyFor()));
            }

            // 邮箱主题
            msg.setSubject(message.getSubject());
            // 邮箱内容
            msg.setText(message.getText());
            // 设置发送时间
            msg.setSentDate(new Date());
            // 发送消息
            Transport.send(msg);
        } catch (Exception e) {
            log.error(">>>邮件发送失败:<<<", e);
            throw new ApplicationException(CommonErrorType.EMAIL_ERROR);
        }
    }

    /**
     * 将多个email地址转换 InternetAddress数组
     *
     * @param emails
     * @return
     */
    private InternetAddress[] trans(String emails) throws Exception {
        InternetAddress[] addresses = null;
        if (StringUtils.isNotBlank(emails)) {
            // 多个收件人用 ;隔开
            String[] split = emails.split(";");

            addresses = new InternetAddress[split.length];

            for (int i = 0; i < split.length; i++) {
                addresses[i] = new InternetAddress(split[i]);
            }
        }
        return addresses;
    }

    private Session createSession() {
        Properties properties = emailUtils.getEmailServerInfo();
        String username = emailUtils.getSender();
        String password = emailUtils.getPassword();

        if (properties == null || StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            log.error(">>>邮件用户名或者密码为空<<<");
            throw new ApplicationException(CommonErrorType.EMAIL_ERROR);
        }

        Session session = Session.getInstance(properties, new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                PasswordAuthentication pa = new PasswordAuthentication(username, password);
                return pa;
            }
        });
        return session;
    }
}